package top.zk123.chain.controller;

import com.alibaba.fastjson.JSON;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.zk123.chain.bean.Certificate;
import top.zk123.chain.bean.CertificateTmp;
import top.zk123.chain.bean.ReturnInfo;
import top.zk123.chain.exception.*;
import top.zk123.chain.service.CertificateService;
import top.zk123.chain.util.GlobalUtils;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

/**
 * 证书相关接口层
 *
 * @author Ke Zhang
 * @since 1.0
 */
@RestController
public class CertificateController {
    @Resource
    public CertificateService certificateService;

    /**
     * 上传单个 Excel 文件
     *
     * @param file 文件
     * @return ReturnInfos
     * @throws WrongFileTypeException 上传类型不匹配
     * @throws FileEmptyException     上传文件为空
     * @throws EmptyStringException   文件后缀名为空
     * @throws FileUploadException    文件上传失败
     */
    @PostMapping(value = "/upload/excel")
    public ReturnInfo uploadExcel(@RequestParam("file") MultipartFile file) throws WrongFileTypeException,
            FileEmptyException, EmptyStringException, FileUploadException {
        return certificateService.uploadExcel(file);
    }

    /**
     * 上传 单张、多张 证书扫描件
     *
     * @param files 文件
     * @return ReturnInfo
     * @throws FileUploadException    文件上传失败
     * @throws WrongFileTypeException 上传类型不匹配
     * @throws FileEmptyException     上传文件为空
     * @throws EmptyStringException   文件后缀名为空
     */
    @PostMapping(value = "/upload/certpic")
    public ReturnInfo uploadCertPic(@RequestParam("files") MultipartFile[] files) throws FileUploadException,
            WrongFileTypeException, FileEmptyException, EmptyStringException {
        return certificateService.uploadImages(files, GlobalUtils.CERT_PIC_PATH);
    }

    /**
     * 上传 单张、多张 用户一寸照
     *
     * @param files 文件
     * @return ReturnInfo
     * @throws FileUploadException    文件上传失败
     * @throws WrongFileTypeException 不支持的文件类型
     * @throws FileEmptyException     文件为空
     * @throws EmptyStringException   文件后缀名为空
     */
    @PostMapping(value = "/upload/userpic")
    public ReturnInfo uploadUserPic(@RequestParam("files") MultipartFile[] files) throws FileUploadException,
            WrongFileTypeException, FileEmptyException, EmptyStringException {
        return certificateService.uploadImages(files, GlobalUtils.USER_PIC_PATH);
    }


    /**
     * 上传单张证书
     *
     * @param certificate 证书
     * @return ReturnInfo
     */
    @PostMapping(value = "/upload/cert/single")
    public ReturnInfo uploadSingleCert(@RequestBody Certificate certificate) {
        return certificateService.uploadSingleCert(certificate);
    }

    /**
     * 批量上传证书
     *
     * @param excel   excel 文件
     * @param userPic 一寸照
     * @param certPic 证书扫描件
     * @return ReturnInfo
     * @throws FileUploadException               文件上传失败
     * @throws WrongFileTypeException            不支持的文件类型
     * @throws FileEmptyException                文件为空
     * @throws EmptyStringException              后缀为空
     * @throws ExcelNotFoundException            Excel数据缺失
     * @throws ExcelParseErrorException          Excel 解析失败
     * @throws ExcelDataLinkToPicFailedException Excel 解析数据与图片数据不符
     */
    @PostMapping(value = "/upload/cert/multi/parse")
    public ReturnInfo parseMultiCert(@RequestParam(value = "excel") MultipartFile excel,
                                     @RequestParam(value = "userPic") MultipartFile[] userPic,
                                     @RequestParam(value = "certPic") MultipartFile[] certPic)
            throws FileUploadException, WrongFileTypeException, FileEmptyException, EmptyStringException,
            ExcelNotFoundException, ExcelParseErrorException, ExcelDataLinkToPicFailedException {
        return certificateService.parseMultipleCert(excel, userPic, certPic);
    }


    /**
     * 保存证书到数据库
     *
     * @return ReturnInfo
     * @throws InvocationTargetException .
     * @throws IllegalAccessException    .
     */
    @PostMapping(value = "/upload/cert/multi/save")
    public ReturnInfo saveMultipleCert() throws InvocationTargetException, IllegalAccessException {
        return certificateService.saveMultipleCert();
    }


    /**
     * 通过 pageNum 分页查询 临时证书库
     *
     * @param pageSize 页数据量
     * @param pageNum  第几页
     * @return ReturnInfo
     */
    @GetMapping(value = "/cert/tmp/list")
    public ReturnInfo getTmpCertList(@RequestParam(value = "pageSize") int pageSize,
                                     @RequestParam(value = "pageNum") int pageNum) {
        return certificateService.getTmpCertListByPage(pageSize, pageNum);
    }

    /**
     * 修改证书某个属性(不包括图片)
     *
     * @param certificateTmp 证书对象
     * @return ReturnInfo
     */
    @PostMapping(value = "/cert/tmp/change")
    public ReturnInfo modifyCertTmp(@RequestBody CertificateTmp certificateTmp) {
        return certificateService.modifyCertTmp(certificateTmp);
    }

    /**
     * 带条件的分页查询
     *
     * @param pageSize    分页大小
     * @param pageNum     当前页
     * @param certType    证书类型
     * @param name        名字
     * @param sex         性别
     * @param userId      身份证号
     * @param certId      证书编号
     * @param issueDate   证书颁发时间
     * @param institution 机构
     * @return ReturnInfo
     */
    @GetMapping(value = "/cert/list")
    public ReturnInfo getCertListByQuery(@RequestParam(value = "pageSize") int pageSize,
                                         @RequestParam(value = "pageNum") int pageNum,
                                         @RequestParam(value = "certType") String certType,
                                         @RequestParam(value = "name") String name,
                                         @RequestParam(value = "sex") String sex,
                                         @RequestParam(value = "userId") String userId,
                                         @RequestParam(value = "certId") String certId,
                                         @RequestParam(value = "issueDate") String issueDate,
                                         @RequestParam(value = "institution") String institution) {
        return certificateService.getCertListByQuery(pageSize, pageNum, certType, name, sex, userId,
                certId, issueDate, institution);
    }

    /**
     * 返回某张证书的详细信息
     *
     * @param UId 证书唯一Id
     * @return ReturnInfo
     */
    @GetMapping(value = "/cert/detail")
    public ReturnInfo getCertDetail(@RequestParam(value = "UId") long UId) throws CertificateNotFoundException {
        return certificateService.getCertDetail(UId);
    }


    /**
     * 删除证书
     *
     * @param UId 证书唯一Id
     * @return ReturnInfo
     * @throws CertificateNotFoundException 证书记录不存在
     */
    @PostMapping(value = "/cert/delete")
    public ReturnInfo deleteCert(@RequestParam(value = "UId") long UId) throws CertificateNotFoundException {
        return certificateService.deleteCert(UId);
    }

    /**
     * 更新证书
     *
     * @param certificate 证书
     * @return ReturnInfo
     */
    @PostMapping(value = "/cert/update")
    public ReturnInfo updateCert(@RequestBody Certificate certificate) {
        return certificateService.updateCert(certificate);
    }

    /**
     * 单张或多张证书上链
     *
     * @param certUIdList 证书 UId 的列表
     * @return ReturnInfo
     */
    @PostMapping(value = "/cert/uptochain")
    public ReturnInfo upload2Chain(@RequestParam(value = "certUId") List<Long> certUIdList) {
        return certificateService.upload2chain(certUIdList);
    }

    /**
     * 所有证书上链
     *
     * @return ReturnInfo
     */
    @PostMapping(value = "/cert/uptochain/all")
    public ReturnInfo uploadAllCertsToChain() {
        return certificateService.uploadAllCertsToChain();
    }

    /**
     * 撤销证书 (单张）
     *
     * @param certUId 证书列表
     * @param pwd     当前账户的密码
     * @param reason  证书撤销原因
     * @return ReturnInfo
     * @throws WrongPasswordException       密码错误
     * @throws CertificateNotFoundException 证书不存在
     * @throws CertRevokedException         证书已被撤销
     */
    @PostMapping(value = "/cert/revoke")
    public ReturnInfo revokeCert(@RequestParam(value = "certUId") long certUId,
                                 @RequestParam(value = "pwd") String pwd,
                                 @RequestParam(value = "reason") String reason) throws
            WrongPasswordException, CertificateNotFoundException, CertRevokedException {
        return certificateService.revokeCert(certUId, pwd, reason);
    }

    /**
     * 分页查询已颁发证书
     *
     * @param pageSize  分页大小
     * @param pageNum   当前分页
     * @param certType  证书类型
     * @param name      姓名
     * @param sex       性别
     * @param userId    身份证号
     * @param certId    证书Id
     * @param issueDate 颁发日期
     * @param certState 证书状态 int 0-未上链 1-上链中 2-已上链 3-已撤销
     * @return ReturnInfo
     */
    @GetMapping(value = "/cert/uptochain/list")
    public ReturnInfo upload2ChainList(@RequestParam(value = "pageSize") int pageSize,
                                       @RequestParam(value = "pageNum") int pageNum,
                                       @RequestParam(value = "certType") String certType,
                                       @RequestParam(value = "name") String name,
                                       @RequestParam(value = "sex") String sex,
                                       @RequestParam(value = "userId") String userId,
                                       @RequestParam(value = "certId") String certId,
                                       @RequestParam(value = "issueDate") String issueDate,
                                       @RequestParam(value = "certState") String certState) {
        return certificateService.upload2ChainList(pageSize, pageNum, certType, name, sex, userId,
                certId, issueDate, certState);
    }

    /**
     * 单张证书上链
     *
     * @param certUId 证书 UId
     * @return ReturnInfo
     * @throws CertificateNotFoundException 证书不存在
     */
    @GetMapping(value = "/chain/upload")
    public ReturnInfo uploadCert2Chain(@RequestParam(value = "certUId") long certUId) throws CertificateNotFoundException, CertsExistOnChainException {
        return certificateService.uploadCert2Chain(certUId);
    }

    /**
     * 从区块链获取证书数据
     *
     * @return ReturnInfo
     */
    @GetMapping(value = "/chain/getCert")
    public ReturnInfo getCertsOnChain() {
        return new ReturnInfo(200, "获取链上数据成功", JSON.toJSON(certificateService.getCertsOnChain()));
    }

}
